package edu.pku.se.chocolate.solver;

import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;

import org.xml.sax.SAXException;

import edu.pku.se.chocolate.datastructure.MessageNumberResponse;
import edu.pku.se.chocolate.datastructure.RequstMessageResponse;
import edu.pku.se.chocolate.datastructure.Tag;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.IBinder;
import android.util.Log;

/**
 * This service handles a long-run background task that fetching new messages
 * number regularly. One can also pass a intent to this service for submitting
 * a new message number task. By doing this, this service will terminate the 
 * running task, fetching as the intent requests, then switch to the regularly 
 * fetching again. If this service is killed by the system, android will restart 
 * it in a proper time. Also, if needed, please manually call requestStop method
 * to stop it.
 * @author Zhiyou Liu
 */
public class FetchMessageNumberService extends Service {

	private class FetchMessageNumberTask extends 
			AsyncTask<ArrayList<Tag>, 
					ArrayList<MessageNumberResponse>,
					ArrayList<MessageNumberResponse>> 
	{
		public FetchMessageNumberService parent;
		private int startId;
		public FetchMessageNumberTask (FetchMessageNumberService p, int sid) {
			super();
			parent = p;
			startId = sid;
		}
		@Override
		protected ArrayList<MessageNumberResponse> doInBackground(ArrayList<Tag>... params) {
			if (this.isCancelled())
				return null;
			MessageFetcher mf = new MessageFetcher();
			ArrayList<MessageNumberResponse> result = null;
			if (params[0] != null)
				try {
					result = mf.getNewMessageNumber(params[0]);
				} catch (IOException e1) {
					e1.printStackTrace();
					Log.i(TAG, e1.toString());
				} catch (SAXException e1) {
					e1.printStackTrace();
					Log.i(TAG, e1.toString());
				}
			if (this.isCancelled())
				return null;
			publishProgress(result);
			ArrayList<Tag> tags_cache = null;
			int sleep_cache = 60;
			int cnt= 0;
			while (true) {
				Log.i("FetchMessageNumberService", "cnt:"+cnt++);
				if (this.isCancelled())
					return null;
				try {
					int freq = sleep_cache*1000;
					Log.i(TAG, "freq = " + freq);
					if (freq == 0) {
						return null;
					}
					Thread.sleep(freq, 0);
				} catch (InterruptedException e) {
					Log.i("FMN", "InterruptedException");
					return null;
					//e.printStackTrace();
				}				
				try {
					try {
						tags_cache = ChocolateSolver.getInstance().getAutoReflashTags();
						sleep_cache = ChocolateSolver.getInstance().getRefleshFrequency();
						//sleep_cache = 15;
					}
					catch (NullPointerException e) {
						Log.i(TAG, "ChocolateSolver is dead, using cache");
					}
					if (tags_cache == null) {
						Log.i(TAG, "ChocolateSolver.getInstance().getAutoReflashTags() return Null");
					}
					result = mf.getNewMessageNumber(tags_cache);
				} catch (IOException e1) {
					e1.printStackTrace();
					Log.i(TAG, e1.toString());
				} catch (SAXException e1) {
					e1.printStackTrace();
					Log.i(TAG, e1.toString());
				}
				if (this.isCancelled())
					return null;
				publishProgress(result);
				if (this.isCancelled())
					return null;
				
			}
			//return null;
		}

		@Override
		protected void onProgressUpdate(ArrayList<MessageNumberResponse>... progress) {
			if (progress[0] != null) {
				Log.i(TAG, "submitting MsgNum result number:  " + progress[0].size());
				Log.i(TAG, "submitting MsgNum result: " + progress[0].toString());
				ChocolateSolver.getInstance().setResponseMessageNumber(progress[0]);
			}
			else {
				Log.i(TAG, "onProgressUpdate hits a null");
			}
		}
		
	     @Override
		protected void onPostExecute(ArrayList<MessageNumberResponse> result) {
	    	 if (parent != null)
	    		 parent.stopSelf(startId);
	     }				

	}

	private static final String TAG = "FetchMessageNumberService";
	
	FetchMessageNumberTask fmnTask = null;
	
	@Override
	public IBinder onBind(Intent arg0) {
		return null;
	}
	

	@Override
	public void onCreate() {
		
	}

	static public class SArrayList implements Serializable{
		/**
		 * I don't know why I need to do this.....
		 */
		private static final long serialVersionUID = -3234782833887687189L;
		ArrayList<Tag> tags = null;
	}		
	
	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		Log.i(TAG, "entering onStartCommand");
		if (fmnTask != null)
			fmnTask.cancel(true);
		fmnTask = new FetchMessageNumberTask(this, startId);
			
		SArrayList sa = (SArrayList)intent.getSerializableExtra("tags");
		//attachBaseContext(this.getApplicationContext());
		//Log.i(TAG, "attachBaseContext: " + getApplicationContext().toString());
		assert(sa != null);
		if (sa.tags != null)
			Log.i(TAG, "sa.tag number ::"+sa.tags.size());
		fmnTask.execute(sa.tags);
		
		// if we are killed, ask system to restart.
		return START_REDELIVER_INTENT;
	}
	

	
	/**
	 * Warp to submit a task.
	 * @param context
	 * @param tags
	 */
	static public void submitTask(Context context, ArrayList<Tag> tags) {
		Log.i(TAG, "entering submitTask");
		Intent d = null;		
		try {
			d.clone();
		}
		catch (Exception e) {
			e.printStackTrace();
		}		
		if (tags != null)
			Log.i(TAG, "tags size = " + tags.size());
		else 
			Log.i(TAG, "tags == null");
		Intent intent = new Intent(context, FetchMessageNumberService.class);
		SArrayList ma = new SArrayList();
		ma.tags = tags;
		intent.putExtra("tags", ma);
		context.startService(intent);

	}
	
	/**
	 * Sending a request to Stop this serivce. 
	 * @param context
	 * context to construct intent and cal stopping method;
	 */
	static public void requestStop(Context context) {
		Intent intent = new Intent(context, FetchMessageNumberService.class);
		context.stopService(intent);
	}
	
    @Override
    public void onDestroy() {
        // Cancel the persistent notification.
       if (fmnTask != null) {
    	   fmnTask.parent = null;
    	   fmnTask.cancel(true);
       }
    }
	
}
